/*
 * Default X32 configuration file
 */

/*
 *		Device list:
 *			0x00: bus id (16 bit, input)
 *			0x01: primary rs232 data port (8 bit, input/output)
 *			0x02: primary rs232 control register (2 bit, input)
 *			0x03: instruction counter (32 bit, input)
 *			0x04: millisecond clock (32 bit, input)
 *			0x05: display (16 bit, output)
 *			0x06: switches (8 bit, input)
 *			0x07: leds (8 bit, output)
 *			0x08: buttons (4 bit, input)
 * 			0x09: processor state register (8 bit input)
 *			0x11: secondary rs232 data port (8 bit, input/output)
 *			0x12: secondary rs232 control register (2 bit, input)
 *			0x14: ps2 uart (8 bit, input/output)
 *			0x15: ps2 status (1 bit, input)
 *			0x20: interrupt enable register (17 bit, input/output)
 *			0x21: software interrupt device (0 bit, output)
 *			0x26: timer 1 (period register) (32 bit, input/output)
 *			0x27: timer 2 (period register) (32 bit, input/output)
 *			0x28: watchdog timer (period register) (32 bit, input/output)
 *			0x30: pdc 1 (32 bit, input)
 *			0x31: pdc 2 (32 bit, input)
 *			0x40: dpc 1 period (32 bit, output)
 *			0x41: dpc 1 width (32 bit, output)
 *			0x42: dpc 2 period (32 bit, output)
 *			0x43: dpc 2 width (32 bit, output)
 *			
 *		Interrupt list:
 *			0x00: trap instruction
 *			0x01: division by zero
 *			0x02: overflow
 *			0x03: out of memory
 *			0x04: software interrupt
 *			0x05: timer 1
 *			0x06: timer 2
 *			0x07: buttons
 *			0x08: switches
 *			0x09: primary rs232 rx
 *			0x0A: primary rs232 tx
 *			0x0B: secondary rs232 rx
 *			0x0C: secondary rs232 tx
 *			0x0D: pdc 1
 *			0x0E: pdc 2
 *			0x0F: ps/2 input
 */


/******************************************************************************
** INCLUDES
******************************************************************************/
/*
 * Includes: each device type connected to the peripheral bus has its own
 *		preprocessor source file, found in the peripherals directory in the x32
 *		source directory. All devices used below must be included. It is safe to
 *		include devices which are not used (and therefore recommended to keep
 *		all includes at all time).
 */
#include "peripherals/1to1.vh"
#include "peripherals/rs232.vh"
#include "peripherals/4x7seg.vh"
#include "peripherals/clock.vh"
#include "peripherals/timer.vh"
#include "peripherals/dpc.vh"
#include "peripherals/pdc.vh"
#include "peripherals/ps2.vh"
#include "peripherals/softint.vh"

/*
 * The following header file contains a list of pin definitions for an easier
 *  connection between device and fpga pin (see the file for available defines)
 */
#include "s3starter_pins.h"

/******************************************************************************
** GENERAL PROJECT SETTINGS
******************************************************************************/
/*
 * Target fpga, currently only 'xs3e400' is supported (spartan 3e 400K gates)
 */
#define TARGET xs3e400
/*
 * The clockspeed the fpga is running on (in Hertz)
 */
#define CLOCKSPEED 50000000

/*
 * ROM Settings: The ROM is copied to the RAM at a processor reset. Two
 *	variables define whereto the ROM is copied: ROM_LOCATION and 
 *	ROM_ADDRESS_BITS.
 *	
 *	The following rules apply to both variables: The least significant
 *		ROM_ADDRESS_BITS bits of ROM_LOCATION must be 0, and the size of the
 *		rom may not be larger than 2^ROM_ADDRESS_BITS.
 *		
 *		Default is a ROM_ADDRESS_BITS of 16, which means a maximum rom of 64KB,
 *		and a ROM_LOCATION of 0x000C0000, or 768K (last 16 bits zero). These 
 *		settings are default for the bootloader. When the bootloader is running
 *		at 768K, the first 768K in RAM are available for programs. When compiling
 *		custom software into the ROM of the X32, these values should be set to
 *		ROM_LOCATION 0x00000000, and ROM_ADDRESS_BITS 32, which places the custom
 *		ROM at address zero, and allows the entire RAM to be written by the ROM.
 */
/*
 * ROM Target location
 */
#define ROM_LOCATION 0x000C0000
/*
 * Number of address bits used by the ROM
 */
#define ROM_ADDRESS_BITS 16

/* 
 *	The reset signal is generated from the following define statements. Two
 *	different reset signals are generated, the initial reset and the normal
 *	reset. The normal reset always resets the x32, the initial reset may only
 *	reset the x32 for the first time. The normal reset is required, the initial
 *	reset is optional.
 *
 *  The vhdl code generated by these statements is as follows:
 *	reset <= '1' 
 *      when (NORMAL_RESET) else 
 *      when (INITIAL_RESET) and first_time = '1' else 
 *      '0'
 *  (the initial reset line is not generated when it is not defined)
 *	
 *	The double reset system is created to allow the use of all 4 buttons on the
 *	Spartan 3 Starter Board, instead of allocating 1 as reset button. Instead,
 *	the normal reset is initiated when all 4 buttons are pressed. The board
 *	however sends an initial pulse on button(3) when it boots up, button(3)
 *	must thus reset the x32 on the first time it triggers.
 *	
 *	Note: buttons is a signal name generated by the 1:1 input device buttons,
 *		watchdog_int is generated by the watchdog timer
 */
#define INITIAL_RESET buttons(3) = '1'
#define NORMAL_RESET buttons = "1111" or watchdog_int = '1'


/******************************************************************************
** X32 CORE SETTINGS
******************************************************************************/
/*
 * Sizes (in bits) for long, int, short and pointer. these currently MUST be
 *  32/32/16/32 (note, a character is always 8 bit)
 */
#define CORE_SIZE_LONG 32
#define CORE_SIZE_INT 32
#define CORE_SIZE_SHORT 16
#define CORE_SIZE_POINTER 32

/******************************************************************************
** GENERAL PERIPHERAL SETTINGS
******************************************************************************/
/*
 * nr of bits of the address bus to use, the amount of devices which can
 * 	maximally be added relates to this number by 2^PERIPHERAL_ADDRESS_BITS-1
 */
#define PERIPHERAL_ADDRESS_BITS 		8
/*
 * nr of bits of he data bus to use. This must currently be set to 32
 */
#define PERIPHERAL_DATA_BITS 				32
/*
 * unique id for an unique peripheral bus setup (this number is returned when
 * 	reading peripheral device 0), use this value to identify a design when 
 * 	working with multiple configurations
 */
#define PERIPHERAL_ID								5
/*
 * device index for the instruction counter (the peripheral will be 
 * 	located at peripherals[index] or 0x80000000 + index * 4) (must be unique)
 *  may be undefined to suppress an instruction counter device
 */
#define INSTRUCTION_COUNTER_INDEX 0x03
/*
 * the processor state register, this is a special register which is connected
 *  to the error output lines of the processor. The error bits are set when the
 *  lines go high (the errors occure), they automatically reset when they are
 *  read. The complete register looks like this:
 *  
 *  bit 7: trapped
 *  bit 6: out of memory
 *  bit 5: <not used>
 *  bit 4: overflow
 *  bit 3: division by zero
 *  bit 2: <not used>
 *  bit 1: simulator
 *  bit 0: booting
 *  
 *  Note that only bit 3 and 4 are actually usefull, bit 0 will always be one
 *  the first time the register is read, otherwise 0 (can be used to detect
 *  if the processor had a "hard" reset, or a "soft" reset (only a hard reset
 *  will result in a rebooting processor). when bit 6 is set, the processor
 *  "hangs", when bit 7 is set, the processor is trapped (and can only be
 *  restarted by a trap generated interrupt).
 *  bit 1 is high when executing on the simulator instead of the hardware x32
 */
#define PROCSTATE_REGISTER_INDEX 0x09
/*
 * define INTERRUPTS_ENABLE to compile the x32 with interrupt support
 */
#define INTERRUPTS_ENABLE
/*
 * nr of devices which can generate an interrupt (number of irq lines). 
 *  irqs may not be shared between devices. 
 */
#define INTERRUPT_COUNT 16
/*
 * nr of critical irq's. critical irq's are not stopped by the global 
 *  interrupt enable flag. all irq's from 0 to INTERRUPT_CRITICAL-1 are
 *  considered critical irq's (usually, TRAP, DIV0, OFL, OOM, SOFTINT)
 */
#define INTERRUPT_CRITICAL 5
/*
 * device index for the interrupt enable register (the peripheral will be 
 * 	located at peripherals[index] or 0x80000000 + index * 4) (must be unique)
 * 	must be defined to use interrupts (otherwise all interrupts will remain
 * 	disables all the time). It may safely remain defined when interrupts are
 * 	disabled, the register won't be created)
 */
#define INTERRUPT_ENABLE_INDEX 0x20
/*
 * trap instruction irq (mostly used by debugging software)
 */
#define TRAP_IRQ 0x00
/*
 * division by zero irq
 */
#define DIV0_IRQ 0x01
/*
 * overflow irq
 */
#define OVERFLOW_IRQ 0x02
/*
 * out of memory irq
 */
#define OOM_IRQ 0x03
/*
 * The following settings define the behaviour of the out of memory irq. 
 *  OOM_LOWER_BOUND should be set to the maximum allowed memory address, and
 *  OOM_UPPER_BOUND should be set to the minimum allowed memory address, and
 *  must be larger than OOM_LOWER_BOUND. The area between OOM_LOWER_BOUND and
 *	OOM_UPPER_BOUND is therefore forbidden. OOM_LOWER_BOUND should be set 
 *	slightly less then the memory size, since some memory space is needed to
 *	handle the out of memory interrupt.
 *	
 *	Note: both values must be smaller than 0x80000000 for xst
 *
 */
/* everything above 0x80000000 is ok (peripherals) */
#define OOM_UPPER_BOUND 0x7FFFFFFF
/* everything below 1020K is ok (leaves 4K for interrupt) */
#define OOM_LOWER_BOUND 0x000FF000


/******************************************************************************
** X32 LIBRARY OPTIONS
******************************************************************************/
/*
 * The following defines must contain code which will be included in x32.h to
 *	generate standard code for the timing, putchar and getchar code (these
 *	defines are included in x32.h, without the LIBCODE_ prefix)
 */
/*
 * Code to get a number which represents time. Both the amount of milliseconds,
 *  and the amount of microseconds running since system reset must be returned.
 *  Both macro's may return 0 when they are not supported, when only one of the
 *  clocks is supported, a division/multiplication by 1000 should be included
 *  in the macro. Note that these clocks may overflow, the programmer should
 *  take care of this
 *	
 *	Usage: t = X32_MS_CLOCK;
 */
#define LIBCODE_X32_MS_CLOCK (peripherals[0x04])
#define LIBCODE_X32_US_CLOCK (peripherals[0x04]*1000)
/* 
 * Code to write a character to stdout
 */
#define LIBCODE_X32_STDOUT (peripherals[0x01])
/*
 * Code to get the status of stdout. This should return nonzero when
 *	it is possible to write to stdout
 *	
 *	Usage: while(!X32_STDOUT_STATUS);
 *	       X32_STDOUT = 'A';
 */
#define LIBCODE_X32_STDOUT_STATUS (peripherals[0x02] & 0x01)
/*
 * Code to read a character from stdin
 */
#define LIBCODE_X32_STDIN (peripherals[0x01])
/*
 * Code to get the status of stdin. This should return nonzero when
 * 	a byte is available to read
 * 	
 * 	Usage: while(!X32_STDIN_STATUS);
 * 	       c = X32_STDIN;
 */
#define LIBCODE_X32_STDIN_STATUS (peripherals[0x02] & 0x02)

/******************************************************************************
** DEVICE LIST
******************************************************************************/

/*
 * 1 to 1 input devices, form a direct connection from an fpga pin to the x32.
 *	
 * Syntax:
 *	ADD_1TO1_INPUT_DEVICE(name, index, int_index, size, pins)
 *		name: the name of the device (must be unique)
 *		index: the peripheral index (the peripheral will be located at
 *			peripherals[index] or 0x80000000 + index * 4) (must be unique)
 *		int_index: the irq for the device (must be unique).
 *		pins: the fpga pin location string (the entire string must be placed
 *			between double quotes. multiple pins must be seperated by a space).
 *			(note: format is compiler dependent)
 */
// spartan 3 starter board switches => x32
ADD_1TO1_INPUT_DEVICE(switches, 0x06, 0x08, 8, PIN_SWITCHES)
// spartan 3 starter board buttons => x32
ADD_1TO1_INPUT_DEVICE(buttons, 0x08, 0x07, 4, PIN_BUTTONS)

/*
 * 1 to 1 output devices, form a direct connection from the x32 to an fpga pin.
 * 
 * Syntax:
 *	ADD_1TO1_OUTPUT_DEVICE(name, index, size, pins)
 *		name: the name of the device (must be unique)
 *		index: the peripheral index (the peripheral will be located at
 *			peripherals[index] or 0x80000000 + index * 4) (must be unique)
 *		pins: the fpga pin location string (the entire string must be placed
 *			between double quotes. multiple pins must be seperated by a space).
 *			(note: format is compiler dependent)
 */
// x32 => spartan 3 starter board leds
ADD_1TO1_OUTPUT_DEVICE(leds, 0x07, 8, PIN_LEDS)

/* 
 * rs232 uart devices, uses 2 peripherals, the binary port which is connected
 * 	to the uarts, and a control register which holds the status of the device.
 * 	A write to the binary port will push the written byte into the buffer and
 * 	will be written to the rs232 tx line. A read from the binary port will 
 * 	return the last bit received on the rs232 rx line. The least significant
 * 	bit of the control register is 1 when the output buffer has room (must be
 * 	checked before writing the binary port). The next least significant bit
 * 	is one when a byte is ready in the input buffer (must be checked before
 * 	reading).
 * 	
 * 	Syntax:
 * 		ADD_RS232_DEVICE(name, index_port, index_control, in_buffer_size,
 * 			out_buffer_size, baudrate, tx_pin, rx_pin, in_irq, out_irq)
 * 			
 * 			name: the name of the device (must be unique)
 * 			index_port: the peripheral index for the binary port (the peripheral 
 * 				will be located at peripherals[index] or 0x80000000 + index * 4) 
 * 				(must be unique)
 * 			index_control: the peripheral index for the control (the peripheral 
 * 				will be located at peripherals[index] or 0x80000000 + index * 4) 
 * 				(must be unique)
 * 			in_buffer_size: number of bytes in the input buffer
 * 			out_buffer_size: number of bytes in the output buffer
 * 			baudrate: the bautrate (constant after compilation)
 * 			tx_pin: the fpga pin location string for the tx line
 *				(the entire string must be placed between double quotes)
 *				(note: format is compiler dependent)
 * 			rx_pin: the fpga pin location string for the rx line
 *				(the entire string must be placed between double quotes
 *				(note: format is compiler dependent)
 * 			in_irq: the irq for incomming bytes (must be unique)
 * 			out_irq: the irq for outgoing bytes (must be unique)
 */
ADD_RS232_DEVICE(primary, 0x01, 0x02, 8, 8, 115200, PIN_PRIMARY_TX, PIN_PRIMARY_RX, 0x09, 0x0A)
ADD_RS232_DEVICE(secondary, 0x11, 0x12, 8, 8, 115200, PIN_SECONDARY_TX, PIN_SECONDARY_RX, 0x0B, 0x0C)


/* 
 * 4x7seg display device, as placed on the spartan 3 starter board. The device
 * 	is 16 bit, and the data is automatically converted from binary data to its
 * 	hexadecimal representation (it is currently not yet possible to control the
 * 	individual segments in the display)
 *
 *	Syntax:
 *		ADD_4x7SEGDISP_DEVICE(name, index, data_pins, control_pins)
 * 			name: the name of the device (must be unique)
 * 			index: the peripheral index for the peripheral (the peripheral 
 * 				will be located at peripherals[index] or 0x80000000 + index * 4) 
 * 				(must be unique)
 * 			data_pins: the fpga pin location string for the eight data lines
 *				(the entire string must be placed between double quotes)
 *				(note: format is compiler dependent)
 * 			control_pins: the fpga pin location string for the four control lines
 *				(the entire string must be placed between double quotes)
 *				(note: format is compiler dependent)
 */
ADD_4x7SEGDISP_DEVICE(display, 0x05, PIN_DISPLAY_DATA, PIN_DISPLAY_CONTROL)

/* 
 * Clock devices count periods of fixed time. They can be used, for example,
 * 	to create a millisecond counter which counts the number of milliseconds
 * 	passed since the last system reset. Counters will eventually overflow, and
 * 	have no support for interrupts. If an interrupt driven system is required,
 * 	use timers instead.
 * 	
 * 	Syntax:
 * 		ADD_CLOCK_DEVICE(name, index, period)
 * 			
 * 			name: the name of the device (must be unique)
 * 			index: the peripheral index (the peripheral will be located at 
 * 			peripherals[index] or 0x80000000 + index * 4) (must be unique)
 * 			period: the number of clockcycles for each counter period (the counter
 * 				adds one to each value, each time this many clockcycles has passed).
 */
ADD_CLOCK_DEVICE(ms_clock, 0x04, 50000)

/*
 * Timer devices are similar to counter devices, except they time a period
 *  which can be set at runtime, and they fire an interrupt when each time
 *  they reach there period (after which they'll reset and restart counting).
 *  
 * Syntax:
 * 		ADD_TIMER_DEVICE(name, index, int_index)
 * 		
 * 			name: the name of the device (must be unique)
 * 			index: the peripheral index for the period register. The period is
 * 				counted in clockcycles (the peripheral will be located at 
 * 				peripherals[index] or 0x80000000 + index * 4) (must be unique)
 * 			int_index: the irq for the device (must be unique).
 */
ADD_TIMER_DEVICE(timer1, 0x26, 0x05)
ADD_TIMER_DEVICE(timer2, 0x27, 0x06)
/*
 * A timer can also be used as a watchdog timer. The timer is created without
 *	interrupt, since it is not required to react on it by software (the
 *	hardware reset must be activated when it triggers). A timer generates a
 *	NAME_int signal (in this case; watchdog_int), which can be used as reset
 *	signal. See above how the reset signal uses the watchdog_int signal.
 */
#undef INTERRUPTS_ENABLE
ADD_TIMER_DEVICE(watchdog, 0x28, 0x00)
#define INTERRUPTS_ENABLE

/*
 * pdc, or pulse to digital convertors. They can be used to sense pulse width
 *	modulated signals. On each rising edge of the input signal, a counter 
 *	starts counting clockcycles. On the falling edge the counter value is
 *	written to a register which is available on the peripheral bus, and an
 *	interrupt is fired. Note that the counter may overflow when the pulse
 *	width is to large (on a 50MHz clock, and a 32-bit peripheral data bus, the
 *	maximum pulse width is slightly less than 86 seconds).
 *
 * Syntax:
 *		ADD_PDC_DEVICE(name, index, int_index, pin)
 *
 * 			name: the name of the device (must be unique)
 * 			index: the peripheral index for the period register. The period is
 * 				counted in clockcycles (the peripheral will be located at 
 * 				peripherals[index] or 0x80000000 + index * 4) (must be unique)
 * 			int_index: the irq for the device (must be unique).
 *			pin: the fpga pin location string (the entire string must be placed
 *				between double quotes. (note: format is compiler dependent)
 */
ADD_PDC_DEVICE(pdc1, 0x30, 0x0D, PIN_EXT_B1_21)
ADD_PDC_DEVICE(pdc2, 0x31, 0x0E, PIN_EXT_B1_23)

/*
 * dpc, or digital to pulse convertors. The counterpart of the pdc, they can be
 * 	used to convert a binary number to a pulse width signal. Both the period
 * 	and the width of the pulse can be set on runtime through the peripheral 
 * 	bus. The same overflow restrictions from the pdc apply to the dpc. Both the
 * 	period, and the pulse width are counted in clockcycles. It is therefore
 * 	possible to generate a pulse with a duty cycle larger than 100% (which will
 * 	result in a flat high output line).
 *
 * Syntax:
 *		ADD_DPC_DEVICE(name, period_index, width_index, pin)
 *
 * 			name: the name of the device (must be unique)
 * 			period_index: the peripheral index for the period register. The period
 * 				is counted in clockcycles (the peripheral will be located at 
 * 				peripherals[index] or 0x80000000 + index * 4) (must be unique)
 * 			width_index: the peripheral index for the width register. The width
 * 				is counted in clockcycles (the peripheral will be located at 
 * 				peripherals[index] or 0x80000000 + index * 4) (must be unique)
 *			pin: the fpga pin location string (the entire string must be placed
 *				between double quotes. (note: format is compiler dependent)
 */
ADD_DPC_DEVICE(dpc1, 0x40, 0x41, PIN_EXT_B1_5)
ADD_DPC_DEVICE(dpc2, 0x42, 0x43, PIN_EXT_B1_7)

/*
 * ps2 uart device. Device used to read/write data from/to the two standard ps2
 *  bidirectional lines (ps2clk and ps2data). 
 *  
 *  Note: this device is still in development. It currently only supports 
 *  	reading the ps2 lines, without buffers and without a status register.
 *  	It is therefore only usable with interrupt support.
 *  	
 * Syntax:
 * 		ADD_PS2_DEVICE(name, data_index, status_index int_index, buff_size, 
 *      ps2clk_pin, ps2data_pin)
 *
 * 			name: the name of the device (must be unique)
 * 			data_index: the peripheral index for the data register. The last 
 * 				received byte can be read from this location (the peripheral will 
 * 				be located at peripherals[index] or 0x80000000 + index * 4) (must 
 *				be unique)
 * 			status_index: the peripheral index for the status register. This will
 * 				return 1 when a byte is available, 0 otherwise (the peripheral will 
 * 				be located at peripherals[index] or 0x80000000 + index * 4) (must 
 *				be unique)
 * 			int_index: the irq for the device (must be unique).
 * 			buff_size: size of the input buffer (bytes)
 *			ps2clk_pin: the fpga pin location string (the entire string must be 
 *				placed between double quotes. (note: format is compiler dependent)
 *			ps2data_pin: the fpga pin location string (the entire string must be 
 *				placed between double quotes. (note: format is compiler dependent)
 */
ADD_PS2_DEVICE(ps2, 0x14, 0x15, 0x0F, 8, PIN_PS2_CLOCK, PIN_PS2_DATA)

/*
 * software interrupt device: this device turns a memory write operation into
 * 	an interrupt raise operation. A write to this device will raise an 
 * 	interrupt on the specified irq. A read operation won't do anything
 *
 * Syntax:
 * 		ADD_SOFTINT_DEVICE(name, index, int_index)
 * 			name: the name of the device (must be unique)
 * 			index: the peripheral index for the data register. The last received
 * 				byte can be read from this location (the peripheral will be located 
 * 				at peripherals[index] or 0x80000000 + index * 4) (must be unique)
 * 			int_index: the irq for the device (must be unique).
 */
ADD_SOFTINT_DEVICE(softint1, 0x21, 0x04)